#include "bsp_csi.h"

/**
 * @brief CSI gpio 初始化
 *
 */
void CSI_GPIO_INIT(void) {
  IOMUXC_SetPinMux(IOMUXC_CSI_VSYNC_CSI_VSYNC, 0);
  IOMUXC_SetPinMux(IOMUXC_CSI_HSYNC_CSI_HSYNC, 0);
  IOMUXC_SetPinMux(IOMUXC_CSI_PIXCLK_CSI_PIXCLK, 0);
  IOMUXC_SetPinMux(IOMUXC_CSI_DATA00_CSI_DATA02, 0);
  IOMUXC_SetPinMux(IOMUXC_CSI_DATA01_CSI_DATA03, 0);
  IOMUXC_SetPinMux(IOMUXC_CSI_DATA02_CSI_DATA04, 0);
  IOMUXC_SetPinMux(IOMUXC_CSI_DATA03_CSI_DATA05, 0);
  IOMUXC_SetPinMux(IOMUXC_CSI_DATA04_CSI_DATA06, 0);
  IOMUXC_SetPinMux(IOMUXC_CSI_DATA05_CSI_DATA07, 0);
  IOMUXC_SetPinMux(IOMUXC_CSI_DATA06_CSI_DATA08, 0);
  IOMUXC_SetPinMux(IOMUXC_CSI_DATA07_CSI_DATA09, 0);

  // gpio_pin_config_t config;
  // config.direction = kGPIO_DigitalInput;
  // config.outputLogic = 0;
  // config.interruptMode = kGPIO_NoIntmode;
  // gpio_init(GPIO4, 19, &config);
  // gpio_init(GPIO4, 20, &config);
  // gpio_init(GPIO4, 18, &config);
  // gpio_init(GPIO4, 21, &config);
  // gpio_init(GPIO4, 22, &config);
  // gpio_init(GPIO4, 23, &config);
  // gpio_init(GPIO4, 24, &config);
  // gpio_init(GPIO4, 25, &config);
  // gpio_init(GPIO4, 26, &config);
  // gpio_init(GPIO4, 27, &config);
  // gpio_init(GPIO4, 28, &config);
}

/**
 * @brief CSI 寄存器初始化
 *
 */
void CSI_INIT() {

  /*
    CSICR1
    [31]    0   SWAP16_EN
    [30]    1   EXT_VSYNC
    [27]    0   VIDEO_MODE
    [20]    1   FB2_DMA_DONE_INTEN
    [19]    1   FB1_DMA_DONE_INTEN
    [11]    1   HSYNC_POL   电平有效
    [10]    0   CCIR_EN
    [8]     0   FCC         FIFO清除方式异步
    [7]     1   PACK_DIR    打包方向
    [5]     1   CLR_RXFIFO  写1清除RXFIFO
    [4]     1   GCLK_MODE
    [3]     0   INV_DATA
    [2]     0   INV_PCLK
    [1]     1   REDGE
    [0]     0   PIXEL_BIT
  */
  CSI->CSICR1 = 0;
  CSI->CSICR1 |= (0x0 << 31 | 0x1 << 30 | 0x0 << 27 | 0x1 << 20 | 0x1 << 19 |
                  0x1 << 11 | 0x0 << 10 | 0x0 << 8 | 0x1 << 7 | 0x1 << 5 |
                  0x1 << 4 | 0x0 << 3 | 0x0 << 2 | 0x1 << 1 | 0x0 << 0);
  while (CSI->CSICR1 & (0x1 << 5)) {
  }

  /*
    CSICR2
    [31-30]	0x2	 DMA_BURST_TYPE_RFF	11 INCR16
   */
  CSI->CSICR2 = 0;
  CSI->CSICR2 |= (0x2 << 30);

  /*
    CSICR3
        [15]	1	FRMCNT_RST
        [14]	1	DMA_REFLASH_RFF
        [6-4]	4	RxFF_LEVEL
        [0]		1	ECC_AUTO_EN
   */
  CSI->CSICR3 = 0;
  CSI->CSICR3 = (0x1 << 15) | (0x1 << 14) | (0X4 << 4) | (0X1 << 0);
  while (CSI->CSICR3 & (0x3 << 14)) {
  }
  /* Frame Buffer Parameter. Indicates the stride of the frame buffer. The width
  of the frame buffer(in ) minus the width of the image(in ) is the stride. The
  stride should be aligned. The embedded DMA controller will skip the stride
  before starting to write the next row of the image. */
  CSI->CSIFBUF_PARA = 0;
}
void csi_reflush_dma() {
  // CSI->CSICR3[14]:置1：刷新DMA控制器
  CSI->CSICR3 |= (0x1 << 14);
  while (CSI->CSICR3 & (0x1 << 14))
    ;
}
// 设置传输地址
void csi_set_tranfer_address(uint32_t address) {
  CSI->CSIDMASA_FB1 = address;
  CSI->CSIDMASA_FB2 = address;
}
// 图像参数初始化
void image_param_init(uint16_t width, uint16_t heght) {
  CSI->CSIIMAG_PARA |= ((width * 2) << 16) | heght << 0;
}
void csi_start_dma() {
  // CSI->CSICR3[12]:置1：使能DMA的请求
  CSI->CSICR3 |= (0x1 << 12);

  //    //CSI->CSICR3[31]:置1:全局使能，csi才可以将接收的数据写入memory
  CSI->CSICR18 |= (0x1 << 31);
}
void csi_stop_dma() {
  // CSI->CSICR3[12]:置0：失能DMA的请求
  CSI->CSICR3 &= ~(0x1 << 12);

  //    //CSI->CSICR3[31]:置0:全局失能，csi才可以将接收的数据写入memory
  CSI->CSICR18 &= ~(0x1 << 31);
}

void csi_control_init() {
  // CSI->CSICR1[31]:no swap
  CSI->CSICR1 &= ~(0X1 << 31);
  // CSI->CSICR1 [30]:External VSYNC mode
  CSI->CSICR1 |= 0x1 << 30;
  // CSI->CSICR1[27]:逐行扫描模式
  CSI->CSICR1 &= ~(0x1 << 27);
  // CSI->CSICR1[20]:置1 Frame Buffer2 DMA Transfer Done interrupt enable
  // CSI->CSICR1[19]:置1 Frame Buffer1 DMA Transfer Done interrupt enable
  CSI->CSICR1 |= (0x3 << 19);
  // CSI->CSICR1[11]:HSYNC(极性的选择）置1:高电平有效 (门控模式)
  CSI->CSICR1 |= (0x1 << 11);
  // CSI->CSICR1[8]:异步清除RXFIFO 置1:异步
  CSI->CSICR1 &= ~(0x1 << 8);
  // CSI->CSICR1[7]:设置打包的方向。置1:高位先行
  CSI->CSICR1 |= (0x1 << 7);
  // CSI->CSICR1[5]:清理RXFIFO 置1:清除，完成后自动归0(在CSI->CSICR1[8] = 0)
  CSI->CSICR1 |= (0x1 << 5);
  while ((CSI->CSICR1 >> 5) & 0x1)
    ;
  // CSI->CSICR1[4]：置1:Gated Clock Mode Enable
  CSI->CSICR1 |= (0x1 << 4);
  // CSI->CSICR1[3]:置1:数据不翻转
  CSI->CSICR1 |= (0x1 << 3);
  // CSI->CSICR1[1]:置1:数据在上升沿采集
  CSI->CSICR1 |= (0x1 << 1);
  // CSI->CSICR1[0]:置1:数据的长度
  CSI->CSICR1 |= (0x1 << 0);

  // CSI->CSICR2[31~30]:置0x3:16个节拍去发送
  CSI->CSICR2 |= (0x3 << 30);

  // CSI->CSICR3[15]:置1:重置计数器,且自动归0
  CSI->CSICR3 |= (0x1 << 15);
  while (CSI->CSICR3 & (0x1 << 15))
    ;

  // CSI->CSICR3[6~4]:置100，32位
  CSI->CSICR3 &= ~(0xf << 4);
  CSI->CSICR3 |= (0x4 << 4);
  // CSI->CSICR3[0]:置1：开启自动纠错
  CSI->CSICR3 |= (0x1 << 0);

  CSI->CSIRFIFO = 0;
}

/**
 * @brief 设置图像格式
 *
 * @param width 	宽
 * @param height 	高
 */
void CSI_Set_Image_Parameter(unsigned short width, unsigned short height) {
  CSI->CSIIMAG_PARA = (width * 2 << 16) | (height);
}

/**
 * @brief 设置DMA地址
 *
 * @param buf
 */
void CSI_DMA_Start_Addr(unsigned int buf) {
  CSI->CSIDMASA_FB1 = buf;
  CSI->CSIDMASA_FB2 = buf;
}

/**
 * @brief CSI_DMA_使能
 *
 * @param judge
 */
void CSI_Enable_DMA(bool judge) {
  if (judge) {
    CSI->CSICR3 |= (0x1 << 12);
    CSI->CSICR18 |= (0x1 << 31);
  } else {
    CSI->CSICR3 &= ~(0x1 << 12);
    CSI->CSICR18 &= ~(0x1 << 31);
  }
}

/**
 * @brief	刷新DMA控制器
 *
 */
void CSI_Refresh_DMA(void) {
  CSI->CSICR3 |= (0x1 << 14);
  while (CSI->CSICR3 & (0x1 << 14)) {
  }
}
